package mymongo

import (
	"mygo/mystruct"
	"context"
	"fmt"
	"reflect"
	"strings"
	"go.mongodb.org/mongo-driver/bson"
)

/* =================================================================================
   权限检查
*/
// 检查对表进行操作权限
func Auth_api_edit(account string, user *mystruct.Muser, results *mystruct.Retdate, code string) (*mystruct.Muser, *mystruct.ModelItem) {
	
	result := Get_Code(code)
	if result == nil {
		results.Code = mystruct.MyCodeErr
		results.Mesg = "表不存在"
		return nil, nil
	}

	if result.Body.Account == "" && user.Standing < mystruct.AUTH_Administrator + 1 {
		results.Code = mystruct.MyCodeErr
		results.Mesg = "这个表未进行用户绑定"
		return nil, result.Body
	}

	if result.Body.Account != user.Account && user.Standing < mystruct.AUTH_Administrator + 1 {
		results.Code = mystruct.MyCodeErr
		results.Mesg = "非此表绑定拥有者不可操作"
		return nil, result.Body
	}
	if account != "" {
		clientsMu.Lock()
		defer clientsMu.Unlock()
		obj, ok := MYUSER_CACHE[account]
		if (ok) {
			return &obj.User, result.Body
		}
	}
	return nil, result.Body
}
// 检查用户权限
func auth_user_edit(account string, user *mystruct.Muser, results *mystruct.Retdate) *mystruct.Muser {
	clientsMu.Lock()
    defer clientsMu.Unlock()

	var result mystruct.Muser

	obj, ok := MYUSER_CACHE[account]
	if (ok) {
		result = obj.User
	}
	if (!ok) {
		ret := MyMonDB.UserCur.FindOne(context.TODO(), bson.M{"account": account})
		if err := ret.Decode(&result); err != nil {
			results.Code = mystruct.MyCodeErr
			results.Mesg = "账号不存在"
			return nil
		}
	}
	if result.Account != user.Account && result.Createuser != user.Account && user.Standing < mystruct.AUTH_Superadmin + 1 {
		if !result.Edit {
			results.Code = mystruct.MyCodeErr
			results.Mesg = "非归属且不可操作"
			return nil
		} 
	}
	if (ok) {
		return &result
	}
	return nil
}


/* =================================================================================
   用户对于表权限操作
*/
// 添加权限
func Add_UserAuth(account, code string, user *mystruct.Muser) *mystruct.Retdate {
	results := &mystruct.Retdate{"Add-UserAuth", mystruct.MyCodeOk, "succeed"}

	chcae_user, _ := Auth_api_edit(account, user, results, code)
	if results.Code != mystruct.MyCodeOk {
		return results
	}

	filter := bson.M{"account": account}
	update := bson.M{"$set": bson.M{"authority": bson.M{}}}
	ctx := context.TODO()
    _, err := MyMonDB.UserCur.UpdateOne(ctx, filter, update)
	if err != nil {
		results.Code = mystruct.MyCodeErr
    	results.Mesg = err.Error()
    	return results
	}
	attributeValue := mystruct.Mroute{false, false, false, false} 
   update = bson.M{"$set": bson.M{fmt.Sprintf("authority.%s", code): attributeValue}}
   _, err = MyMonDB.UserCur.UpdateOne(ctx, filter, update)
   if err != nil {
    	results.Code = mystruct.MyCodeErr
    	results.Mesg = err.Error()
    	return results
   }

	if chcae_user != nil {
		if chcae_user.Authority == nil {
			chcae_user.Authority = make(map[string]mystruct.Mroute)
		}
		chcae_user.Authority[code] = attributeValue
	}
	return results
}
// 删除权限
func Del_UserAuth(account, code string, user *mystruct.Muser) *mystruct.Retdate {
	results := &mystruct.Retdate{"Del-UserAuth", mystruct.MyCodeOk, "succeed"}

	chcae_user, _ := Auth_api_edit(account, user, results, code)
	if results.Code != mystruct.MyCodeOk {
		return results
	}

	filter := bson.M{"account": account}
   update := bson.M{"$unset": bson.M{fmt.Sprintf("authority.%s", code): ""}}
   _, err := MyMonDB.UserCur.UpdateOne(context.TODO(), filter, update)
   if err != nil {
    	results.Code = mystruct.MyCodeErr
    	results.Mesg = err.Error()
   }

	if chcae_user != nil {
		if chcae_user.Authority != nil {
			delete(chcae_user.Authority, code)
		}
	}
	return results
}
// 修改权限
func Set_UserAuth(account, field string, strVal interface{}, code string, user *mystruct.Muser) *mystruct.Retdate {
	results := &mystruct.Retdate{"Set-UserAuth", mystruct.MyCodeOk, "succeed"}

	chcae_user, _ := Auth_api_edit(account, user, results, code)
	if results.Code != mystruct.MyCodeOk {
		return results
	}

	update := bson.D{{"$set", bson.D{bson.E{Key: field, Value: strVal}}}}
	ret, err := MyMonDB.UserCur.UpdateOne(context.TODO(), bson.M{"account": account}, update)
	if err != nil {
		results.Code = mystruct.MyCodeErr
		results.Mesg = err.Error()
		return results
	}
	results.Code = ret.ModifiedCount

	if chcae_user == nil {
		return results
	}
	currentField := reflect.ValueOf(chcae_user).Elem()
	fieldNames := strings.Split(field, ".")
	for index, fieldName := range fieldNames {
		fieldName = strings.ToUpper(fieldName[:1]) + fieldName[1:]
		switch currentField.Kind() {
		   case reflect.Struct:
		      currentField = currentField.FieldByName(fieldName)
		   case reflect.Map:
		      adminKey := reflect.ValueOf(fieldName)
		      adminValue := currentField.MapIndex(adminKey)
		      if adminValue.IsValid() && adminValue.Type() == reflect.TypeOf(mystruct.Mroute{}) {
					newAdminValue := reflect.New(reflect.TypeOf(mystruct.Mroute{})).Elem()
					for i := 0; i < adminValue.NumField(); i++ {
						field := adminValue.Field(i)
						newAdminValue.Field(i).Set(field)
					}
					fieldName = fieldNames[index+1]
					fieldName = strings.ToUpper(fieldName[:1]) + fieldName[1:]
					newAdminValue.FieldByName(fieldName).SetBool(strVal.(bool))
					currentField.SetMapIndex(adminKey, newAdminValue)
				}
				break
		   default:
		      return results
	   }
	   if !currentField.IsValid() {
         return results
      }
	}
	if currentField.CanSet() {
		switch currentField.Kind() {
			case reflect.Bool:
				boolVal, isBool := strVal.(bool)
		        if isBool {
		            currentField.SetBool(boolVal)
		        }
			case reflect.String:
				str, isString := strVal.(string)
		         if isString {
		            currentField.SetString(str)
		         }
		}
	}
	return results
}